#include "Lexico.h"

Lexico::Lexico(Hash &mHashRecebido)
{
	this->mHash = &mHashRecebido;
	this->mFlag = false;
	this->mErro = false;
	this->mLinha = 1;
}

void Lexico::GetLinha(Arquivo &mArquivo)
{
	//recebe a linha lida no arquivo
	this->mBuffer = mArquivo.GetLinha();	
	
}
// valida � chamada cada vez q uma linha � lida
void Lexico::Valida()
{
		int mCont = 0; //contador para buffer
		
		if( this->mFlag == true )
		{
			
			while(mBuffer[mCont] != '*' ||  mBuffer[mCont+1] != ')')
			{
				   if(mBuffer[mCont] == '\n')
				   {
				   		this->mFlag = true;
				   		return;
				   }
				   mCont++;	
			}
			mCont = mCont+2;    
			this->mFlag = false;
		}
		
				
		while( mBuffer[mCont] != '\0' ) // n�o fim de buffer
		{	
					
					//insere um identificador valido
					if( EhLetra(mBuffer[mCont]) ) // fazer metodo caracter valido
					{
						
						string mAux;//string auxiliar
						while(  EhLetra(mBuffer[mCont]) || Numero(mBuffer[mCont]) )
							{
								
								
									mAux.push_back(mBuffer[mCont]);
									mCont++;
								
							}
						if(CaracterValido(mBuffer[mCont]))
						{
							if(mHash->Pesquisa(mAux))
							    mLista.InsereLista(mAux, 1);
							else        
								mLista.InsereLista(mAux,2);
						
						}else
						{
							mCont++;
							while(  EhLetra(mBuffer[mCont]) || Numero(mBuffer[mCont]) || !CaracterValido(mBuffer[mCont]) )
							{
								
								mCont++;
							}
							//insere na lista de erros
							Lexico::InsereErro(1);
							
							
						}					
					}else
					{	
						
						
						//insere um operando
						if(this->Operadores(mCont))
							continue;						   
												
						if( this->Numero(mBuffer[mCont]) )
						{
							if( EhLetra(mBuffer[mCont+1]) )
							{
								// erro
								mCont++;
								while(  EhLetra(mBuffer[mCont]) || Numero(mBuffer[mCont]) || !CaracterValido(mBuffer[mCont]))
								{
									mCont++;
								}
								//insere na lista de 
								Lexico::InsereErro(2);
								
								
							}
							else
							{	
							    EhNumero(mCont);
							}
							continue;
						}
						//pila linha			
						if (mBuffer[mCont] == '\n')
						{ 
							this->mLinha++;
							break;
						}
						else 
							{
								
								this->InsereErro(4); //caracter invalido
								 mCont++;
							}
					}
			}
						
					
}


bool Lexico::Operadores(int &mCont)
{
	//insere um identificador valido
	switch(mBuffer[mCont])
	{
		case ' ': mCont++; return true; //espa�o em branco
		case ',':mLista.InsereLista(",",4);mCont++;return true;//tipo 1
		case ';':mLista.InsereLista(";",4);mCont++;return true;
		case '.':mLista.InsereLista(".",4);mCont++;return true;
		case '/':mLista.InsereLista("/",4);mCont++;return true;
		case '+':mLista.InsereLista("+",4);mCont++;return true;
		case '*':mLista.InsereLista("*",4);mCont++;return true;
		//case '(':mLista.InsereLista("(",4);mCont++;return true;
		case ')':mLista.InsereLista(")",4);mCont++;return true;
		case '-':mLista.InsereLista("-",4);mCont++;return true;
		
		case '<':if (mBuffer[++mCont] == '=')
						{
							mLista.InsereLista("<=",4);mCont++;
							return true;
						}
				  else 
				  {
				  		if(mBuffer[mCont] == '>')
				  			{ mLista.InsereLista("<>",4); mCont++;return true;}
				  		mLista.InsereLista("<",4);
				  		return true;
				  }
				  
		
		case '>':if (mBuffer[++mCont] == '=')
						{mLista.InsereLista(">=",4);mCont++;}
				  else 
				  		{mLista.InsereLista(">",4);}
				 return true;
				 
		case ':': if (mBuffer[++mCont] == '=')
						{mLista.InsereLista(":=",4);mCont++;}
				  else 
				  		{mLista.InsereLista(":",4);}
				return true;			
		
		case '=':mLista.InsereLista("=",4);mCont++;return true;
		
		case '(': if (mBuffer[++mCont] == '*')
				  {
							mCont++;
							
							while(mBuffer[mCont] != '*' ||  mBuffer[mCont+1] != ')')
							{
							   if(mBuffer[mCont] == '\n')
							   {
							   		this->mFlag = true;
							   		return true;
							   }
							   mCont++;	
							   
							}
												    
							mCont = mCont+2;    
						    return true;
					}
					else{
						mLista.InsereLista("(",4);
						return true;
					} 			
		case '[':mLista.InsereLista("[",4);mCont++;return true;		
		case ']':mLista.InsereLista("]",4);mCont++;return true;
		
		case '\'': string mAux; //string q devera ser impressa
				   mLista.InsereLista("'",4);  
				   while( mBuffer[++mCont] != '\'' )
				   {
				   	   mAux.push_back(mBuffer[mCont]);
				   } 
				   mCont++;
				   mLista.InsereLista(mAux,5);  //insere a string na lista
				   mLista.InsereLista("'",4);  
				   return true;
	}
	
	return false;
	
	
}


void Lexico::mostra()
{
	mLista.mostra();
}


bool Lexico::EhLetra(char mTeste)
{
	if( (mTeste >= 'a'&& mTeste <= 'z') || mTeste == '_' || (mTeste >= 'A'&& mTeste <= 'Z'))
	    return true;
	else
	{
	    mErro = true;
	    return false;
	}
}

bool Lexico::EhNumero(int &mCont)
{
	string mAux;
	while( Numero(mBuffer[mCont] ))
	{
		mAux.push_back( mBuffer[mCont] );
		mCont++;		
	}	
	
	mLista.InsereLista(mAux,3);
	return true;
	
}
bool Lexico::Numero(char mTeste)
{
	return (mTeste >= '0'&& mTeste <= '9')?true:false;
}

bool Lexico::CaracterValido(char mAux)
{
	if ( Numero( mAux ) )
		return true;
	if( EhLetra(mAux) )
		return true;
	if ( mAux == ' ' || mAux == ',' || mAux == ';' || mAux == '.' || mAux == '/' || mAux == '+'
	     || mAux == '*' || mAux == '-' || mAux == '<' || mAux == '>' || mAux == ':'
	     || mAux == '=' || mAux == '{' || mAux == '}' || mAux == '[' || mAux == ']'
	     || mAux == '(' || mAux == ')' || mAux == '\'')
		return true;
	return false;
	
	
}

void Lexico::InsereErro( int mTipo )
{
	TipoErro mErr;
	mErr.mLinha = mLinha;
	mErr.mTipo = mTipo; //tipo de erro 1
	this->mListaErros.push_back(mErr);						
}

void Lexico::MostraErro(Arquivo & mSaida )
{
	TipoErro mErro;
	for( int i = 0 ; i < mListaErros.size() ; i++ )
	{
		mErro = mListaErros.at(i);
		mSaida.ImprimeErro(mErro.mLinha ,mErro.mTipo);
	}
}

void Lexico::RetLista(ListaIdentificadores & mIdentificadores)
{
	mIdentificadores = this->mLista;
	
}


Lexico::~Lexico()
{
}
